home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / generic / tclListObj.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  31.4 KB  |  1,054 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tclListObj.c --
  3.  *
  4.  *    This file contains procedures that implement the Tcl list object
  5.  *    type.
  6.  *
  7.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tclListObj.c 1.47 97/08/12 19:02:02
  13.  */
  14.  
  15. #include "tclInt.h"
  16.  
  17. /*
  18.  * Prototypes for procedures defined later in this file:
  19.  */
  20.  
  21. static void        DupListInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
  22.                 Tcl_Obj *copyPtr));
  23. static void        FreeListInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr));
  24. static int        SetListFromAny _ANSI_ARGS_((Tcl_Interp *interp,
  25.                 Tcl_Obj *objPtr));
  26. static void        UpdateStringOfList _ANSI_ARGS_((Tcl_Obj *listPtr));
  27.  
  28. /*
  29.  * The structure below defines the list Tcl object type by means of
  30.  * procedures that can be invoked by generic object code.
  31.  */
  32.  
  33. Tcl_ObjType tclListType = {
  34.     "list",                /* name */
  35.     FreeListInternalRep,        /* freeIntRepProc */
  36.     DupListInternalRep,                /* dupIntRepProc */
  37.     UpdateStringOfList,            /* updateStringProc */
  38.     SetListFromAny            /* setFromAnyProc */
  39. };
  40.  
  41. /*
  42.  *----------------------------------------------------------------------
  43.  *
  44.  * Tcl_NewListObj --
  45.  *
  46.  *    This procedure is normally called when not debugging: i.e., when
  47.  *    TCL_MEM_DEBUG is not defined. It creates a new list object from an
  48.  *    (objc,objv) array: that is, each of the objc elements of the array
  49.  *    referenced by objv is inserted as an element into a new Tcl object.
  50.  *
  51.  *    When TCL_MEM_DEBUG is defined, this procedure just returns the
  52.  *    result of calling the debugging version Tcl_DbNewListObj.
  53.  *
  54.  * Results:
  55.  *    A new list object is returned that is initialized from the object
  56.  *    pointers in objv. If objc is less than or equal to zero, an empty
  57.  *    object is returned. The new object's string representation
  58.  *    is left NULL. The resulting new list object has ref count 0.
  59.  *
  60.  * Side effects:
  61.  *    The ref counts of the elements in objv are incremented since the
  62.  *    resulting list now refers to them.
  63.  *
  64.  *----------------------------------------------------------------------
  65.  */
  66.  
  67. #ifdef TCL_MEM_DEBUG
  68. #undef Tcl_NewListObj
  69.  
  70. Tcl_Obj *
  71. Tcl_NewListObj(objc, objv)
  72.     int objc;            /* Count of objects referenced by objv. */
  73.     Tcl_Obj *CONST objv[];    /* An array of pointers to Tcl objects. */
  74. {
  75.     return Tcl_DbNewListObj(objc, objv, "unknown", 0);
  76. }
  77.  
  78. #else /* if not TCL_MEM_DEBUG */
  79.  
  80. Tcl_Obj *
  81. Tcl_NewListObj(objc, objv)
  82.     int objc;            /* Count of objects referenced by objv. */
  83.     Tcl_Obj *CONST objv[];    /* An array of pointers to Tcl objects. */
  84. {
  85.     register Tcl_Obj *listPtr;
  86.     register Tcl_Obj **elemPtrs;
  87.     register List *listRepPtr;
  88.     int i;
  89.     
  90.     TclNewObj(listPtr);
  91.     
  92.     if (objc > 0) {
  93.     Tcl_InvalidateStringRep(listPtr);
  94.     
  95.     elemPtrs = (Tcl_Obj **)
  96.         ckalloc((unsigned) (objc * sizeof(Tcl_Obj *)));
  97.     for (i = 0;  i < objc;  i++) {
  98.         elemPtrs[i] = objv[i];
  99.         Tcl_IncrRefCount(elemPtrs[i]);
  100.     }
  101.     
  102.     listRepPtr = (List *) ckalloc(sizeof(List));
  103.     listRepPtr->maxElemCount = objc;
  104.     listRepPtr->elemCount    = objc;
  105.     listRepPtr->elements     = elemPtrs;
  106.     
  107.     listPtr->internalRep.otherValuePtr = (VOID *) listRepPtr;
  108.     listPtr->typePtr = &tclListType;
  109.     }
  110.     return listPtr;
  111. }
  112. #endif /* if TCL_MEM_DEBUG */
  113.  
  114. /*
  115.  *----------------------------------------------------------------------
  116.  *
  117.  * Tcl_DbNewListObj --
  118.  *
  119.  *    This procedure is normally called when debugging: i.e., when
  120.  *    TCL_MEM_DEBUG is defined. It creates new list objects. It is the
  121.  *    same as the Tcl_NewListObj procedure above except that it calls
  122.  *    Tcl_DbCkalloc directly with the file name and line number from its
  123.  *    caller. This simplifies debugging since then the checkmem command
  124.  *    will report the correct file name and line number when reporting
  125.  *    objects that haven't been freed.
  126.  *
  127.  *    When TCL_MEM_DEBUG is not defined, this procedure just returns the
  128.  *    result of calling Tcl_NewListObj.
  129.  *
  130.  * Results:
  131.  *    A new list object is returned that is initialized from the object
  132.  *    pointers in objv. If objc is less than or equal to zero, an empty
  133.  *    object is returned. The new object's string representation
  134.  *    is left NULL. The new list object has ref count 0.
  135.  *
  136.  * Side effects:
  137.  *    The ref counts of the elements in objv are incremented since the
  138.  *    resulting list now refers to them.
  139.  *
  140.  *----------------------------------------------------------------------
  141.  */
  142.  
  143. #ifdef TCL_MEM_DEBUG
  144.  
  145. Tcl_Obj *
  146. Tcl_DbNewListObj(objc, objv, file, line)
  147.     int objc;            /* Count of objects referenced by objv. */
  148.     Tcl_Obj *CONST objv[];    /* An array of pointers to Tcl objects. */
  149.     char *file;            /* The name of the source file calling this
  150.                  * procedure; used for debugging. */
  151.     int line;            /* Line number in the source file; used
  152.                  * for debugging. */
  153. {
  154.     register Tcl_Obj *listPtr;
  155.     register Tcl_Obj **elemPtrs;
  156.     register List *listRepPtr;
  157.     int i;
  158.     
  159.     TclDbNewObj(listPtr, file, line);
  160.     
  161.     if (objc > 0) {
  162.     Tcl_InvalidateStringRep(listPtr);
  163.     
  164.     elemPtrs = (Tcl_Obj **)
  165.         ckalloc((unsigned) (objc * sizeof(Tcl_Obj *)));
  166.     for (i = 0;  i < objc;  i++) {
  167.         elemPtrs[i] = objv[i];
  168.         Tcl_IncrRefCount(elemPtrs[i]);
  169.     }
  170.     
  171.     listRepPtr = (List *) ckalloc(sizeof(List));
  172.     listRepPtr->maxElemCount = objc;
  173.     listRepPtr->elemCount    = objc;
  174.     listRepPtr->elements     = elemPtrs;
  175.     
  176.     listPtr->internalRep.otherValuePtr = (VOID *) listRepPtr;
  177.     listPtr->typePtr = &tclListType;
  178.     }
  179.     return listPtr;
  180. }
  181.  
  182. #else /* if not TCL_MEM_DEBUG */
  183.  
  184. Tcl_Obj *
  185. Tcl_DbNewListObj(objc, objv, file, line)
  186.     int objc;            /* Count of objects referenced by objv. */
  187.     Tcl_Obj *CONST objv[];    /* An array of pointers to Tcl objects. */
  188.     char *file;            /* The name of the source file calling this
  189.                  * procedure; used for debugging. */
  190.     int line;            /* Line number in the source file; used
  191.                  * for debugging. */
  192. {
  193.     return Tcl_NewListObj(objc, objv);
  194. }
  195. #endif /* TCL_MEM_DEBUG */
  196.  
  197. /*
  198.  *----------------------------------------------------------------------
  199.  *
  200.  * Tcl_SetListObj --
  201.  *
  202.  *    Modify an object to be a list containing each of the objc elements
  203.  *    of the object array referenced by objv.
  204.  *
  205.  * Results:
  206.  *    None.
  207.  *
  208.  * Side effects:
  209.  *    The object is made a list object and is initialized from the object
  210.  *    pointers in objv. If objc is less than or equal to zero, an empty
  211.  *    object is returned. The new object's string representation
  212.  *    is left NULL. The ref counts of the elements in objv are incremented
  213.  *    since the list now refers to them. The object's old string and
  214.  *    internal representations are freed and its type is set NULL.
  215.  *
  216.  *----------------------------------------------------------------------
  217.  */
  218.  
  219. void
  220. Tcl_SetListObj(objPtr, objc, objv)
  221.     Tcl_Obj *objPtr;        /* Object whose internal rep to init. */
  222.     int objc;            /* Count of objects referenced by objv. */
  223.     Tcl_Obj *CONST objv[];    /* An array of pointers to Tcl objects. */
  224. {
  225.     register Tcl_Obj **elemPtrs;
  226.     register List *listRepPtr;
  227.     Tcl_ObjType *oldTypePtr = objPtr->typePtr;
  228.     int i;
  229.  
  230.     if (Tcl_IsShared(objPtr)) {
  231.     panic("Tcl_SetListObj called with shared object");
  232.     }
  233.     
  234.     /*
  235.      * Free any old string rep and any internal rep for the old type.
  236.      */
  237.  
  238.     Tcl_InvalidateStringRep(objPtr);
  239.     if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
  240.     oldTypePtr->freeIntRepProc(objPtr);
  241.     objPtr->typePtr = NULL;
  242.     }
  243.         
  244.     /*
  245.      * Set the object's type to "list" and initialize the internal rep.
  246.      */
  247.  
  248.     if (objc > 0) {
  249.     elemPtrs = (Tcl_Obj **)
  250.         ckalloc((unsigned) (objc * sizeof(Tcl_Obj *)));
  251.     for (i = 0;  i < objc;  i++) {
  252.         elemPtrs[i] = objv[i];
  253.         Tcl_IncrRefCount(elemPtrs[i]);
  254.     }
  255.     
  256.     listRepPtr = (List *) ckalloc(sizeof(List));
  257.     listRepPtr->maxElemCount = objc;
  258.     listRepPtr->elemCount    = objc;
  259.     listRepPtr->elements     = elemPtrs;
  260.     
  261.     objPtr->internalRep.otherValuePtr = (VOID *) listRepPtr;
  262.     objPtr->typePtr = &tclListType;
  263.     }
  264. }
  265.  
  266. /*
  267.  *----------------------------------------------------------------------
  268.  *
  269.  * Tcl_ListObjGetElements --
  270.  *
  271.  *    This procedure returns an (objc,objv) array of the elements in a
  272.  *    list object.
  273.  *
  274.  * Results:
  275.  *    The return value is normally TCL_OK; in this case *objcPtr is set to
  276.  *    the count of list elements and *objvPtr is set to a pointer to an
  277.  *    array of (*objcPtr) pointers to each list element. If listPtr does
  278.  *    not refer to a list object and the object can not be converted to
  279.  *    one, TCL_ERROR is returned and an error message will be left in
  280.  *    the interpreter's result if interp is not NULL.
  281.  *
  282.  *    The objects referenced by the returned array should be treated as
  283.  *    readonly and their ref counts are _not_ incremented; the caller must
  284.  *    do that if it holds on to a reference. Furthermore, the pointer
  285.  *    and length returned by this procedure may change as soon as any
  286.  *    procedure is called on the list object; be careful about retaining
  287.  *    the pointer in a local data structure.
  288.  *
  289.  * Side effects:
  290.  *    The possible conversion of the object referenced by listPtr
  291.  *    to a list object.
  292.  *
  293.  *----------------------------------------------------------------------
  294.  */
  295.  
  296. int
  297. Tcl_ListObjGetElements(interp, listPtr, objcPtr, objvPtr)
  298.     Tcl_Interp *interp;        /* Used to report errors if not NULL. */
  299.     register Tcl_Obj *listPtr;    /* List object for which an element array
  300.                  * is to be returned. */
  301.     int *objcPtr;        /* Where to store the count of objects
  302.                  * referenced by objv. */
  303.     Tcl_Obj ***objvPtr;        /* Where to store the pointer to an array
  304.                  * of pointers to the list's objects. */
  305. {
  306.     register List *listRepPtr;
  307.  
  308.     if (listPtr->typePtr != &tclListType) {
  309.     int result = SetListFromAny(interp, listPtr);
  310.     if (result != TCL_OK) {
  311.         return result;
  312.     }
  313.     }
  314.     listRepPtr = (List *) listPtr->internalRep.otherValuePtr;
  315.     *objcPtr = listRepPtr->elemCount;
  316.     *objvPtr = listRepPtr->elements;
  317.     return TCL_OK;
  318. }
  319.  
  320. /*
  321.  *----------------------------------------------------------------------
  322.  *
  323.  * Tcl_ListObjAppendList --
  324.  *
  325.  *    This procedure appends the objects in the list referenced by
  326.  *    elemListPtr to the list object referenced by listPtr. If listPtr is
  327.  *    not already a list object, an attempt will be made to convert it to
  328.  *    one.
  329.  *
  330.  * Results:
  331.  *    The return value is normally TCL_OK. If listPtr or elemListPtr do
  332.  *    not refer to list objects and they can not be converted to one,
  333.  *    TCL_ERROR is returned and an error message is left in
  334.  *    the interpreter's result if interp is not NULL.
  335.  *
  336.  * Side effects:
  337.  *    The reference counts of the elements in elemListPtr are incremented
  338.  *    since the list now refers to them. listPtr and elemListPtr are
  339.  *    converted, if necessary, to list objects. Also, appending the
  340.  *    new elements may cause listObj's array of element pointers to grow.
  341.  *    listPtr's old string representation, if any, is invalidated.
  342.  *
  343.  *----------------------------------------------------------------------
  344.  */
  345.  
  346. int
  347. Tcl_ListObjAppendList(interp, listPtr, elemListPtr)
  348.     Tcl_Interp *interp;        /* Used to report errors if not NULL. */
  349.     register Tcl_Obj *listPtr;    /* List object to append elements to. */
  350.     Tcl_Obj *elemListPtr;    /* List obj with elements to append. */
  351. {
  352.     register List *listRepPtr;
  353.     int listLen, objc, result;
  354.     Tcl_Obj **objv;
  355.  
  356.     if (Tcl_IsShared(listPtr)) {
  357.     panic("Tcl_ListObjAppendList called with shared object");
  358.     }
  359.     if (listPtr->typePtr != &tclListType) {
  360.     result = SetListFromAny(interp, listPtr);
  361.     if (result != TCL_OK) {
  362.         return result;
  363.     }
  364.     }
  365.     listRepPtr = (List *) listPtr->internalRep.otherValuePtr;
  366.     listLen = listRepPtr->elemCount;
  367.  
  368.     result = Tcl_ListObjGetElements(interp, elemListPtr, &objc, &objv);
  369.     if (result != TCL_OK) {
  370.     return result;
  371.     }
  372.  
  373.     /*
  374.      * Insert objc new elements starting after the lists's last element.
  375.      * Delete zero existing elements.
  376.      */
  377.     
  378.     return Tcl_ListObjReplace(interp, listPtr, listLen, 0, objc, objv);
  379. }
  380.  
  381. /*
  382.  *----------------------------------------------------------------------
  383.  *
  384.  * Tcl_ListObjAppendElement --
  385.  *
  386.  *    This procedure is a special purpose version of
  387.  *    Tcl_ListObjAppendList: it appends a single object referenced by
  388.  *    objPtr to the list object referenced by listPtr. If listPtr is not
  389.  *    already a list object, an attempt will be made to convert it to one.
  390.  *
  391.  * Results:
  392.  *    The return value is normally TCL_OK; in this case objPtr is added
  393.  *    to the end of listPtr's list. If listPtr does not refer to a list
  394.  *    object and the object can not be converted to one, TCL_ERROR is
  395.  *    returned and an error message will be left in the interpreter's
  396.  *    result if interp is not NULL.
  397.  *
  398.  * Side effects:
  399.  *    The ref count of objPtr is incremented since the list now refers 
  400.  *    to it. listPtr will be converted, if necessary, to a list object.
  401.  *    Also, appending the new element may cause listObj's array of element
  402.  *    pointers to grow. listPtr's old string representation, if any,
  403.  *    is invalidated.
  404.  *
  405.  *----------------------------------------------------------------------
  406.  */
  407.  
  408. int
  409. Tcl_ListObjAppendElement(interp, listPtr, objPtr)
  410.     Tcl_Interp *interp;        /* Used to report errors if not NULL. */
  411.     Tcl_Obj *listPtr;        /* List object to append objPtr to. */
  412.     Tcl_Obj *objPtr;        /* Object to append to listPtr's list. */
  413. {
  414.     register List *listRepPtr;
  415.     register Tcl_Obj **elemPtrs;
  416.     int numElems, numRequired;
  417.     
  418.     if (Tcl_IsShared(listPtr)) {
  419.     panic("Tcl_ListObjAppendElement called with shared object");
  420.     }
  421.     if (listPtr->typePtr != &tclListType) {
  422.     int result = SetListFromAny(interp, listPtr);
  423.     if (result != TCL_OK) {
  424.         return result;
  425.     }
  426.     }
  427.  
  428.     listRepPtr = (List *) listPtr->internalRep.otherValuePtr;
  429.     elemPtrs = listRepPtr->elements;
  430.     numElems = listRepPtr->elemCount;
  431.     numRequired = numElems + 1 ;
  432.     
  433.     /*
  434.      * If there is no room in the current array of element pointers,
  435.      * allocate a new, larger array and copy the pointers to it.
  436.      */
  437.  
  438.     if (numRequired > listRepPtr->maxElemCount) {
  439.     int newMax = (2 * numRequired);
  440.     Tcl_Obj **newElemPtrs = (Tcl_Obj **)
  441.         ckalloc((unsigned) (newMax * sizeof(Tcl_Obj *)));
  442.     
  443.     memcpy((VOID *) newElemPtrs, (VOID *) elemPtrs,
  444.            (size_t) (numElems * sizeof(Tcl_Obj *)));
  445.  
  446.     listRepPtr->maxElemCount = newMax;
  447.     listRepPtr->elements = newElemPtrs;
  448.     ckfree((char *) elemPtrs);
  449.     elemPtrs = newElemPtrs;
  450.     }
  451.  
  452.     /*
  453.      * Add objPtr to the end of listPtr's array of element
  454.      * pointers. Increment the ref count for the (now shared) objPtr.
  455.      */
  456.  
  457.     elemPtrs[numElems] = objPtr;
  458.     Tcl_IncrRefCount(objPtr);
  459.     listRepPtr->elemCount++;
  460.  
  461.     /*
  462.      * Invalidate any old string representation since the list's internal
  463.      * representation has changed.
  464.      */
  465.  
  466.     Tcl_InvalidateStringRep(listPtr);
  467.     return TCL_OK;
  468. }
  469.  
  470. /*
  471.  *----------------------------------------------------------------------
  472.  *
  473.  * Tcl_ListObjIndex --
  474.  *
  475.  *    This procedure returns a pointer to the index'th object from the
  476.  *    list referenced by listPtr. The first element has index 0. If index
  477.  *    is negative or greater than or equal to the number of elements in
  478.  *    the list, a NULL is returned. If listPtr is not a list object, an
  479.  *    attempt will be made to convert it to a list.
  480.  *
  481.  * Results:
  482.  *    The return value is normally TCL_OK; in this case objPtrPtr is set
  483.  *    to the Tcl_Obj pointer for the index'th list element or NULL if
  484.  *    index is out of range. This object should be treated as readonly and
  485.  *    its ref count is _not_ incremented; the caller must do that if it
  486.  *    holds on to the reference. If listPtr does not refer to a list and
  487.  *    can't be converted to one, TCL_ERROR is returned and an error
  488.  *    message is left in the interpreter's result if interp is not NULL.
  489.  *
  490.  * Side effects:
  491.  *    listPtr will be converted, if necessary, to a list object.
  492.  *
  493.  *----------------------------------------------------------------------
  494.  */
  495.  
  496. int
  497. Tcl_ListObjIndex(interp, listPtr, index, objPtrPtr)
  498.     Tcl_Interp *interp;        /* Used to report errors if not NULL. */
  499.     register Tcl_Obj *listPtr;    /* List object to index into. */
  500.     register int index;        /* Index of element to return. */
  501.     Tcl_Obj **objPtrPtr;    /* The resulting Tcl_Obj* is stored here. */
  502. {
  503.     register List *listRepPtr;
  504.     
  505.     if (listPtr->typePtr != &tclListType) {
  506.     int result = SetListFromAny(interp, listPtr);
  507.     if (result != TCL_OK) {
  508.         return result;
  509.     }
  510.     }
  511.  
  512.     listRepPtr = (List *) listPtr->internalRep.otherValuePtr;
  513.     if ((index < 0) || (index >= listRepPtr->elemCount)) {
  514.     *objPtrPtr = NULL;
  515.     } else {
  516.     *objPtrPtr = listRepPtr->elements[index];
  517.     }
  518.     
  519.     return TCL_OK;
  520. }
  521.  
  522. /*
  523.  *----------------------------------------------------------------------
  524.  *
  525.  * Tcl_ListObjLength --
  526.  *
  527.  *    This procedure returns the number of elements in a list object. If
  528.  *    the object is not already a list object, an attempt will be made to
  529.  *    convert it to one.
  530.  *
  531.  * Results:
  532.  *    The return value is normally TCL_OK; in this case *intPtr will be
  533.  *    set to the integer count of list elements. If listPtr does not refer
  534.  *    to a list object and the object can not be converted to one,
  535.  *    TCL_ERROR is returned and an error message will be left in
  536.  *    the interpreter's result if interp is not NULL.
  537.  *
  538.  * Side effects:
  539.  *    The possible conversion of the argument object to a list object.
  540.  *
  541.  *----------------------------------------------------------------------
  542.  */
  543.  
  544. int
  545. Tcl_ListObjLength(interp, listPtr, intPtr)
  546.     Tcl_Interp *interp;        /* Used to report errors if not NULL. */
  547.     register Tcl_Obj *listPtr;    /* List object whose #elements to return. */
  548.     register int *intPtr;    /* The resulting int is stored here. */
  549. {
  550.     register List *listRepPtr;
  551.     
  552.     if (listPtr->typePtr != &tclListType) {
  553.     int result = SetListFromAny(interp, listPtr);
  554.     if (result != TCL_OK) {
  555.         return result;
  556.     }
  557.     }
  558.  
  559.     listRepPtr = (List *) listPtr->internalRep.otherValuePtr;
  560.     *intPtr = listRepPtr->elemCount;
  561.     return TCL_OK;
  562. }
  563.  
  564. /*
  565.  *----------------------------------------------------------------------
  566.  *
  567.  * Tcl_ListObjReplace --
  568.  * 
  569.  *    This procedure replaces zero or more elements of the list referenced
  570.  *    by listPtr with the objects from an (objc,objv) array. 
  571.  *    The objc elements of the array referenced by objv replace the
  572.  *    count elements in listPtr starting at first.
  573.  *
  574.  *    If the argument first is zero or negative, it refers to the first
  575.  *    element. If first is greater than or equal to the number of elements
  576.  *    in the list, then no elements are deleted; the new elements are
  577.  *    appended to the list. Count gives the number of elements to
  578.  *    replace. If count is zero or negative then no elements are deleted;
  579.  *    the new elements are simply inserted before first.
  580.  *
  581.  *    The argument objv refers to an array of objc pointers to the new
  582.  *    elements to be added to listPtr in place of those that were
  583.  *    deleted. If objv is NULL, no new elements are added. If listPtr is
  584.  *    not a list object, an attempt will be made to convert it to one.
  585.  *
  586.  * Results:
  587.  *    The return value is normally TCL_OK. If listPtr does
  588.  *    not refer to a list object and can not be converted to one,
  589.  *    TCL_ERROR is returned and an error message will be left in
  590.  *    the interpreter's result if interp is not NULL.
  591.  *
  592.  * Side effects:
  593.  *    The ref counts of the objc elements in objv are incremented since
  594.  *    the resulting list now refers to them. Similarly, the ref counts for
  595.  *    replaced objects are decremented. listPtr is converted, if
  596.  *    necessary, to a list object. listPtr's old string representation, if
  597.  *    any, is freed. 
  598.  *
  599.  *----------------------------------------------------------------------
  600.  */
  601.  
  602. int
  603. Tcl_ListObjReplace(interp, listPtr, first, count, objc, objv)
  604.     Tcl_Interp *interp;        /* Used for error reporting if not NULL. */
  605.     Tcl_Obj *listPtr;        /* List object whose elements to replace. */
  606.     int first;            /* Index of first element to replace. */
  607.     int count;            /* Number of elements to replace. */
  608.     int objc;            /* Number of objects to insert. */
  609.     Tcl_Obj *CONST objv[];    /* An array of objc pointers to Tcl objects
  610.                  * to insert. */
  611. {
  612.     List *listRepPtr;
  613.     register Tcl_Obj **elemPtrs, **newPtrs;
  614.     Tcl_Obj *victimPtr;
  615.     int numElems, numRequired, numAfterLast;
  616.     int start, shift, newMax, i, j, result;
  617.      
  618.     if (Tcl_IsShared(listPtr)) {
  619.     panic("Tcl_ListObjReplace called with shared object");
  620.     }
  621.     if (listPtr->typePtr != &tclListType) {
  622.     result = SetListFromAny(interp, listPtr);
  623.     if (result != TCL_OK) {
  624.         return result;
  625.     }
  626.     }
  627.     listRepPtr = (List *) listPtr->internalRep.otherValuePtr;
  628.     elemPtrs = listRepPtr->elements;
  629.     numElems = listRepPtr->elemCount;
  630.  
  631.     if (first < 0)  {
  632.         first = 0;
  633.     }
  634.     if (first >= numElems) {
  635.     first = numElems;    /* so we'll insert after last element */
  636.     }
  637.     if (count < 0) {
  638.     count = 0;
  639.     }
  640.     
  641.     numRequired = (numElems - count + objc);
  642.     if (numRequired <= listRepPtr->maxElemCount) {
  643.     /*
  644.      * Enough room in the current array. First "delete" count
  645.      * elements starting at first.
  646.      */
  647.  
  648.     for (i = 0, j = first;  i < count;  i++, j++) {
  649.         victimPtr = elemPtrs[j];
  650.         TclDecrRefCount(victimPtr);
  651.     }
  652.  
  653.     /*
  654.      * Shift the elements after the last one removed to their
  655.      * new locations.
  656.      */
  657.  
  658.     start = (first + count);
  659.     numAfterLast = (numElems - start);
  660.     shift = (objc - count);    /* numNewElems - numDeleted */
  661.     if ((numAfterLast > 0) && (shift != 0)) {
  662.         Tcl_Obj **src, **dst;
  663.  
  664.         if (shift < 0) {
  665.         for (src = elemPtrs + start, dst = src + shift;
  666.             numAfterLast > 0; numAfterLast--, src++, dst++) {
  667.             *dst = *src;
  668.         }
  669.         } else {
  670.         for (src = elemPtrs + numElems - 1, dst = src + shift;
  671.             numAfterLast > 0; numAfterLast--, src--, dst--) {
  672.             *dst = *src;
  673.         }
  674.         }
  675.     }
  676.  
  677.     /*
  678.      * Insert the new elements into elemPtrs before "first".
  679.      */
  680.  
  681.     for (i = 0, j = first;  i < objc;  i++, j++) {
  682.             elemPtrs[j] = objv[i];
  683.             Tcl_IncrRefCount(objv[i]);
  684.         }
  685.  
  686.     /*
  687.      * Update the count of elements.
  688.      */
  689.  
  690.     listRepPtr->elemCount = numRequired;
  691.     } else {
  692.     /*
  693.      * Not enough room in the current array. Allocate a larger array and
  694.      * insert elements into it. 
  695.      */
  696.  
  697.     newMax = (2 * numRequired);
  698.     newPtrs = (Tcl_Obj **)
  699.         ckalloc((unsigned) (newMax * sizeof(Tcl_Obj *)));
  700.  
  701.     /*
  702.      * Copy over the elements before "first".
  703.      */
  704.  
  705.     if (first > 0) {
  706.         memcpy((VOID *) newPtrs, (VOID *) elemPtrs,
  707.             (size_t) (first * sizeof(Tcl_Obj *)));
  708.     }
  709.  
  710.     /*
  711.      * "Delete" count elements starting at first.
  712.      */
  713.  
  714.     for (i = 0, j = first;  i < count;  i++, j++) {
  715.         victimPtr = elemPtrs[j];
  716.         TclDecrRefCount(victimPtr);
  717.     }
  718.  
  719.     /*
  720.      * Copy the elements after the last one removed, shifted to
  721.      * their new locations.
  722.      */
  723.  
  724.     start = (first + count);
  725.     numAfterLast = (numElems - start);
  726.     if (numAfterLast > 0) {
  727.         memcpy((VOID *) &(newPtrs[first + objc]),
  728.             (VOID *) &(elemPtrs[start]),
  729.             (size_t) (numAfterLast * sizeof(Tcl_Obj *)));
  730.     }
  731.     
  732.     /*
  733.      * Insert the new elements before "first" and update the
  734.      * count of elements.
  735.      */
  736.  
  737.     for (i = 0, j = first;  i < objc;  i++, j++) {
  738.         newPtrs[j] = objv[i];
  739.         Tcl_IncrRefCount(objv[i]);
  740.     }
  741.  
  742.     listRepPtr->elemCount = numRequired;
  743.     listRepPtr->maxElemCount = newMax;
  744.     listRepPtr->elements = newPtrs;
  745.     ckfree((char *) elemPtrs);
  746.     }
  747.     
  748.     /*
  749.      * Invalidate and free any old string representation since it no longer
  750.      * reflects the list's internal representation.
  751.      */
  752.  
  753.     Tcl_InvalidateStringRep(listPtr);
  754.     return TCL_OK;
  755. }
  756.  
  757. /*
  758.  *----------------------------------------------------------------------
  759.  *
  760.  * FreeListInternalRep --
  761.  *
  762.  *    Deallocate the storage associated with a list object's internal
  763.  *    representation.
  764.  *
  765.  * Results:
  766.  *    None.
  767.  *
  768.  * Side effects:
  769.  *    Frees listPtr's List* internal representation and sets listPtr's
  770.  *    internalRep.otherValuePtr to NULL. Decrements the ref counts
  771.  *    of all element objects, which may free them.
  772.  *
  773.  *----------------------------------------------------------------------
  774.  */
  775.  
  776. static void
  777. FreeListInternalRep(listPtr)
  778.     Tcl_Obj *listPtr;        /* List object with internal rep to free. */
  779. {
  780.     register List *listRepPtr = (List *) listPtr->internalRep.otherValuePtr;
  781.     register Tcl_Obj **elemPtrs = listRepPtr->elements;
  782.     register Tcl_Obj *objPtr;
  783.     int numElems = listRepPtr->elemCount;
  784.     int i;
  785.     
  786.     for (i = 0;  i < numElems;  i++) {
  787.     objPtr = elemPtrs[i];
  788.     Tcl_DecrRefCount(objPtr);
  789.     }
  790.     ckfree((char *) elemPtrs);
  791.     ckfree((char *) listRepPtr);
  792. }
  793.  
  794. /*
  795.  *----------------------------------------------------------------------
  796.  *
  797.  * DupListInternalRep --
  798.  *
  799.  *    Initialize the internal representation of a list Tcl_Obj to a
  800.  *    copy of the internal representation of an existing list object. 
  801.  *
  802.  * Results:
  803.  *    None.
  804.  *
  805.  * Side effects:
  806.  *    "srcPtr"s list internal rep pointer should not be NULL and we assume
  807.  *    it is not NULL. We set "copyPtr"s internal rep to a pointer to a
  808.  *    newly allocated List structure that, in turn, points to "srcPtr"s
  809.  *    element objects. Those element objects are not actually copied but
  810.  *    are shared between "srcPtr" and "copyPtr". The ref count of each
  811.  *    element object is incremented.
  812.  *
  813.  *----------------------------------------------------------------------
  814.  */
  815.  
  816. static void
  817. DupListInternalRep(srcPtr, copyPtr)
  818.     Tcl_Obj *srcPtr;        /* Object with internal rep to copy. */
  819.     Tcl_Obj *copyPtr;        /* Object with internal rep to set. */
  820. {
  821.     List *srcListRepPtr = (List *) srcPtr->internalRep.otherValuePtr;
  822.     int numElems = srcListRepPtr->elemCount;
  823.     int maxElems = srcListRepPtr->maxElemCount;
  824.     register Tcl_Obj **srcElemPtrs = srcListRepPtr->elements;
  825.     register Tcl_Obj **copyElemPtrs;
  826.     register List *copyListRepPtr;
  827.     int i;
  828.  
  829.     /*
  830.      * Allocate a new List structure that points to "srcPtr"s element
  831.      * objects. Increment the ref counts for those (now shared) element
  832.      * objects.
  833.      */
  834.     
  835.     copyElemPtrs = (Tcl_Obj **)
  836.     ckalloc((unsigned) maxElems * sizeof(Tcl_Obj *));
  837.     for (i = 0;  i < numElems;  i++) {
  838.     copyElemPtrs[i] = srcElemPtrs[i];
  839.     Tcl_IncrRefCount(copyElemPtrs[i]);
  840.     }
  841.     
  842.     copyListRepPtr = (List *) ckalloc(sizeof(List));
  843.     copyListRepPtr->maxElemCount = maxElems;
  844.     copyListRepPtr->elemCount    = numElems;
  845.     copyListRepPtr->elements     = copyElemPtrs;
  846.     
  847.     copyPtr->internalRep.otherValuePtr = (VOID *) copyListRepPtr;
  848.     copyPtr->typePtr = &tclListType;
  849. }
  850.  
  851. /*
  852.  *----------------------------------------------------------------------
  853.  *
  854.  * SetListFromAny --
  855.  *
  856.  *    Attempt to generate a list internal form for the Tcl object
  857.  *    "objPtr".
  858.  *
  859.  * Results:
  860.  *    The return value is TCL_OK or TCL_ERROR. If an error occurs during
  861.  *    conversion, an error message is left in the interpreter's result
  862.  *    unless "interp" is NULL.
  863.  *
  864.  * Side effects:
  865.  *    If no error occurs, a list is stored as "objPtr"s internal
  866.  *    representation.
  867.  *
  868.  *----------------------------------------------------------------------
  869.  */
  870.  
  871. static int
  872. SetListFromAny(interp, objPtr)
  873.     Tcl_Interp *interp;        /* Used for error reporting if not NULL. */
  874.     Tcl_Obj *objPtr;        /* The object to convert. */
  875. {
  876.     Tcl_ObjType *oldTypePtr = objPtr->typePtr;
  877.     char *string, *elemStart, *nextElem, *s;
  878.     int lenRemain, length, estCount, elemSize, hasBrace, i, j, result;
  879.     char *limit;        /* Points just after string's last byte. */
  880.     register char *p;
  881.     register Tcl_Obj **elemPtrs;
  882.     register Tcl_Obj *elemPtr;
  883.     List *listRepPtr;
  884.  
  885.     /*
  886.      * Get the string representation. Make it up-to-date if necessary.
  887.      */
  888.  
  889.     string = TclGetStringFromObj(objPtr, &length);
  890.  
  891.     /*
  892.      * Parse the string into separate string objects, and create a List
  893.      * structure that points to the element string objects. We use a
  894.      * modified version of Tcl_SplitList's implementation to avoid one
  895.      * malloc and a string copy for each list element. First, estimate the
  896.      * number of elements by counting the number of space characters in the
  897.      * list.
  898.      */
  899.  
  900.     limit = (string + length);
  901.     estCount = 1;
  902.     for (p = string;  p < limit;  p++) {
  903.     if (isspace(UCHAR(*p))) {
  904.         estCount++;
  905.     }
  906.     }
  907.  
  908.     /*
  909.      * Allocate a new List structure with enough room for "estCount"
  910.      * elements. Each element is a pointer to a Tcl_Obj with the appropriate
  911.      * string rep. The initial "estCount" elements are set using the
  912.      * corresponding "argv" strings.
  913.      */
  914.  
  915.     elemPtrs = (Tcl_Obj **)
  916.         ckalloc((unsigned) (estCount * sizeof(Tcl_Obj *)));
  917.     for (p = string, lenRemain = length, i = 0;
  918.         lenRemain > 0;
  919.         p = nextElem, lenRemain = (limit - nextElem), i++) {
  920.     result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem,
  921.                 &elemSize, &hasBrace);
  922.     if (result != TCL_OK) {
  923.         for (j = 0;  j < i;  j++) {
  924.         elemPtr = elemPtrs[j];
  925.         Tcl_DecrRefCount(elemPtr);
  926.         }
  927.         ckfree((char *) elemPtrs);
  928.         return result;
  929.     }
  930.     if (elemStart >= limit) {
  931.         break;
  932.     }
  933.     if (i > estCount) {
  934.         panic("SetListFromAny: bad size estimate for list");
  935.     }
  936.  
  937.     /*
  938.      * Allocate a Tcl object for the element and initialize it from the
  939.      * "elemSize" bytes starting at "elemStart".
  940.      */
  941.  
  942.     s = ckalloc((unsigned) elemSize + 1);
  943.     if (hasBrace) {
  944.         memcpy((VOID *) s, (VOID *) elemStart,  (size_t) elemSize);
  945.         s[elemSize] = 0;
  946.     } else {
  947.         elemSize = TclCopyAndCollapse(elemSize, elemStart, s);
  948.     }
  949.     
  950.     TclNewObj(elemPtr);
  951.         elemPtr->bytes  = s;
  952.         elemPtr->length = elemSize;
  953.         elemPtrs[i] = elemPtr;
  954.     Tcl_IncrRefCount(elemPtr); /* since list now holds ref to it */
  955.     }
  956.  
  957.     listRepPtr = (List *) ckalloc(sizeof(List));
  958.     listRepPtr->maxElemCount = estCount;
  959.     listRepPtr->elemCount    = i;
  960.     listRepPtr->elements     = elemPtrs;
  961.  
  962.     /*
  963.      * Free the old internalRep before setting the new one. We do this as
  964.      * late as possible to allow the conversion code, in particular
  965.      * Tcl_GetStringFromObj, to use that old internalRep.
  966.      */
  967.  
  968.     if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
  969.     oldTypePtr->freeIntRepProc(objPtr);
  970.     }
  971.  
  972.     objPtr->internalRep.otherValuePtr = (VOID *) listRepPtr;
  973.     objPtr->typePtr = &tclListType;
  974.     return TCL_OK;
  975. }
  976.  
  977. /*
  978.  *----------------------------------------------------------------------
  979.  *
  980.  * UpdateStringOfList --
  981.  *
  982.  *    Update the string representation for a list object.
  983.  *    Note: This procedure does not invalidate an existing old string rep
  984.  *    so storage will be lost if this has not already been done. 
  985.  *
  986.  * Results:
  987.  *    None.
  988.  *
  989.  * Side effects:
  990.  *    The object's string is set to a valid string that results from
  991.  *    the list-to-string conversion. This string will be empty if the
  992.  *    list has no elements. The list internal representation
  993.  *    should not be NULL and we assume it is not NULL.
  994.  *
  995.  *----------------------------------------------------------------------
  996.  */
  997.  
  998. static void
  999. UpdateStringOfList(listPtr)
  1000.     Tcl_Obj *listPtr;        /* List object with string rep to update. */
  1001. {
  1002. #   define LOCAL_SIZE 20
  1003.     int localFlags[LOCAL_SIZE], *flagPtr;
  1004.     List *listRepPtr = (List *) listPtr->internalRep.otherValuePtr;
  1005.     int numElems = listRepPtr->elemCount;
  1006.     register int i;
  1007.     char *elem, *dst;
  1008.     int length;
  1009.  
  1010.     /*
  1011.      * Convert each element of the list to string form and then convert it
  1012.      * to proper list element form, adding it to the result buffer.
  1013.      */
  1014.  
  1015.     /*
  1016.      * Pass 1: estimate space, gather flags.
  1017.      */
  1018.  
  1019.     if (numElems <= LOCAL_SIZE) {
  1020.     flagPtr = localFlags;
  1021.     } else {
  1022.     flagPtr = (int *) ckalloc((unsigned) numElems*sizeof(int));
  1023.     }
  1024.     listPtr->length = 1;
  1025.     for (i = 0; i < numElems; i++) {
  1026.     elem = Tcl_GetStringFromObj(listRepPtr->elements[i], &length);
  1027.     listPtr->length += Tcl_ScanCountedElement(elem, length,
  1028.         &flagPtr[i]) + 1;
  1029.     }
  1030.  
  1031.     /*
  1032.      * Pass 2: copy into string rep buffer.
  1033.      */
  1034.  
  1035.     listPtr->bytes = ckalloc((unsigned) listPtr->length);
  1036.     dst = listPtr->bytes;
  1037.     for (i = 0; i < numElems; i++) {
  1038.     elem = Tcl_GetStringFromObj(listRepPtr->elements[i], &length);
  1039.     dst += Tcl_ConvertCountedElement(elem, length, dst, flagPtr[i]);
  1040.     *dst = ' ';
  1041.     dst++;
  1042.     }
  1043.     if (flagPtr != localFlags) {
  1044.     ckfree((char *) flagPtr);
  1045.     }
  1046.     if (dst == listPtr->bytes) {
  1047.     *dst = 0;
  1048.     } else {
  1049.     dst--;
  1050.     *dst = 0;
  1051.     }
  1052.     listPtr->length = dst - listPtr->bytes;
  1053. }
  1054.